Spring IOC(控制反转)

ℹ️定位说明

Spring 系列第 1 篇(九部分系统讲解,1660 行)。核心回答:对象为什么交给容器创建——从"问题的提出"到 BeanFactory/ApplicationContext 容器组件、实际应用、与反射的结合、性能与最佳实践。前置:Class 对象与反射机制

第一部分:问题的提出

一、传统方式的困境

想象一个场景:

// 传统方式:手动创建对象和管理依赖
public class OrderService {
    private OrderRepository orderRepository;
    private UserService userService;
    private PaymentService paymentService;

    public OrderService() {
        // 需要手动创建所有依赖
        this.orderRepository = new OrderRepository();
        this.userService = new UserService();
        this.paymentService = new PaymentService();
    }

    public void createOrder(Order order) {
        // 业务逻辑
        userService.validateUser(order.getUserId());
        orderRepository.save(order);
        paymentService.processPayment(order);
    }
}

// 使用时也要手动创建
OrderService orderService = new OrderService();
orderService.createOrder(order);

这种方式有什么问题?

  1. 耦合度高 - 直接依赖具体实现类,修改实现需要改动多处代码
  2. 难以扩展 - 要替换实现类需要修改构造函数
  3. 难以测试 - 单元测试无法mock依赖
  4. 代码冗长 - 重复的对象创建代码
  5. 依赖链复杂 - 如果OrderRepository还有其他依赖,会形成复杂的依赖链
OrderService
  ├─ OrderRepository
  │   ├─ Database
  │   └─ Logger
  ├─ UserService
  │   ├─ UserRepository
  │   └─ Cache
  └─ PaymentService
      ├─ PaymentGateway
      └─ Logger

二、理想的解决方案

我们希望能这样写:

// 理想方式:只声明依赖,框架自动处理
@Service
public class OrderService {
    @Autowired
    private OrderRepository orderRepository;

    @Autowired
    private UserService userService;

    @Autowired
    private PaymentService paymentService;

    public void createOrder(Order order) {
        // 只关注业务逻辑
        userService.validateUser(order.getUserId());
        orderRepository.save(order);
        paymentService.processPayment(order);
    }
}

// 使用时直接注入,无需创建
@Autowired
private OrderService orderService;

orderService.createOrder(order);  // 直接使用

这就是IOC要解决的问题:让框架自动管理对象的创建和依赖注入。


第二部分:IOC的核心概念

三、什么是IOC?

3.1 IOC的定义

IOC(Inversion of Control,控制反转)是一种设计思想,核心是把对象的创建权和依赖管理权从代码中交给框架容器来管理。

┌──────────────────────────────────────────┐
│         IOC的本质                         │
├──────────────────────────────────────────┤
│                                          │
│  传统方式:                               │
│  ├─ 程序员手动创建对象                    │
│  ├─ 程序员手动管理依赖                    │
│  └─ 程序员控制对象的生命周期              │
│                                          │
│  IOC方式:                                │
│  ├─ 框架自动创建对象                      │
│  ├─ 框架自动管理依赖                      │
│  └─ 框架控制对象的生命周期                │
│                                          │
│  控制反转:                               │
│  └─ 控制权从程序员手里反转到框架手里        │
│                                          │
└──────────────────────────────────────────┘

3.2 IOC与GC的类比

┌──────────────────────────────────────────┐
│      IOC与GC的思想对比                    │
├──────────────────────────────────────────┤
│                                          │
│  垃圾回收(GC)                           │
│  ├─ 问题:什么时候释放对象                │
│  ├─ 解决:自动回收不用的对象              │
│  └─ 效果:程序员不用手动释放内存          │
│                                          │
│  控制反转(IOC)                          │
│  ├─ 问题:什么时候创建对象、怎么注入依赖  │
│  ├─ 解决:框架自动创建和注入              │
│  └─ 效果:程序员不用手动创建对象          │
│                                          │
│  共同点:                                 │
│  ├─ 都是"自动化"思想                     │
│  ├─ 都是"把细节交给框架"                 │
│  └─ 都是"程序员专注业务逻辑"             │
│                                          │
└──────────────────────────────────────────┘

3.3 IOC的核心优势

┌──────────────────────────────────────────┐
│         IOC的核心优势                     │
├──────────────────────────────────────────┤
│                                          │
│  1. 解耦                                  │
│     ├─ 依赖接口而不是实现                │
│     ├─ 实现类可以随意替换                │
│     └─ 修改不会影响调用方                │
│                                          │
│  2. 灵活性                                │
│     ├─ 通过配置选择不同实现              │
│     ├─ 支持条件装配                      │
│     └─ 支持动态代理和增强                │
│                                          │
│  3. 可测试性                              │
│     ├─ 容易mock依赖                      │
│     ├─ 支持单元测试                      │
│     └─ 支持集成测试                      │
│                                          │
│  4. 自动化                                │
│     ├─ 自动创建对象                      │
│     ├─ 自动注入依赖                      │
│     └─ 自动管理生命周期                  │
│                                          │
└──────────────────────────────────────────┘

第三部分:IOC的实现原理

四、Spring IOC的四个阶段

4.1 阶段概览

┌──────────────────────────────────────────┐
│      Spring IOC的四个阶段                 │
├──────────────────────────────────────────┤
│                                          │
│  第1阶段:容器启动                        │
│  ├─ 加载配置文件/配置类                  │
│  ├─ 创建IOC容器实例                      │
│  └─ 准备开始管理Bean                     │
│                                          │
│  第2阶段:Bean定义注册                    │
│  ├─ 扫描类路径                           │
│  ├─ 读取注解或XML配置                    │
│  ├─ 创建BeanDefinition                   │
│  └─ 注册到容器                           │
│                                          │
│  第3阶段:实例化和依赖注入                │
│  ├─ 通过反射创建Bean实例                 │
│  ├─ 递归注入依赖                         │
│  ├─ 支持多种注入方式                     │
│  └─ 处理循环依赖                         │
│                                          │
│  第4阶段:初始化Bean                      │
│  ├─ 执行@PostConstruct方法               │
│  ├─ 执行InitializingBean接口             │
│  ├─ 执行BeanPostProcessor                │
│  └─ Bean准备就绪                         │
│                                          │
└──────────────────────────────────────────┘

4.2 第一阶段:容器启动

// 容器启动的三种方式

// 方式1:基于XML配置
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

// 方式2:基于注解配置类
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

// 方式3:Spring Boot自动启动
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

// 容器启动的工作流程
public class ContainerStartupDemo {
    public static void main(String[] args) {
        // 1. 加载配置
        // 2. 创建BeanFactory
        // 3. 创建ApplicationContext
        // 4. 准备开始扫描和注册Bean
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 5. 容器启动完成,可以获取Bean
        UserService userService = context.getBean(UserService.class);
    }
}

4.3 第二阶段:Bean定义注册

// Bean定义注册的过程

// 1. 定义Bean
@Component
public class UserService {
    @Autowired
    private UserRepository userRepository;
}

@Component
public class UserRepository {
    // ...
}

// 2. Spring扫描注解
// ClassPathBeanDefinitionScanner会扫描@Component及其衍生注解

// 3. 创建BeanDefinition
// BeanDefinition是Bean的"说明书",包含:
public class BeanDefinitionDemo {
    // BeanDefinition包含的信息:
    // - 类名:com.example.UserService
    // - 作用域:singleton(单例)或prototype(原型)
    // - 是否懒加载:false
    // - 初始化方法:@PostConstruct标注的方法
    // - 销毁方法:@PreDestroy标注的方法
    // - 依赖信息:@Autowired标注的字段
    // - 其他元数据
}

// 4. 注册到容器
// BeanDefinitionRegistry会把BeanDefinition注册到容器中

BeanDefinition的结构:

public interface BeanDefinition {
    // 获取Bean的类名
    String getBeanClassName();

    // 获取作用域(singleton或prototype)
    String getScope();

    // 是否是单例
    boolean isSingleton();

    // 是否是原型
    boolean isPrototype();

    // 是否懒加载
    boolean isLazyInit();

    // 获取初始化方法名
    String getInitMethodName();

    // 获取销毁方法名
    String getDestroyMethodName();

    // 获取构造函数参数
    ConstructorArgumentValues getConstructorArgumentValues();

    // 获取属性值
    MutablePropertyValues getPropertyValues();
}

4.4 第三阶段:实例化和依赖注入

// 实例化和依赖注入的过程

public class BeanInstantiationDemo {
    // 假设有这样的Bean
    @Component
    public class OrderService {
        @Autowired
        private OrderRepository orderRepository;

        @Autowired
        private UserService userService;
    }

    // Spring的处理流程:

    // 1. 获取OrderService的BeanDefinition
    BeanDefinition beanDef = beanFactory.getBeanDefinition("orderService");

    // 2. 通过反射创建实例
    Class<?> beanClass = Class.forName(beanDef.getBeanClassName());
    OrderService orderService = beanClass.getDeclaredConstructor().newInstance();

    // 3. 检查依赖
    Field[] fields = beanClass.getDeclaredFields();
    for (Field field : fields) {
        if (field.isAnnotationPresent(Autowired.class)) {
            // 4. 递归创建依赖的Bean
            Object dependency = beanFactory.getBean(field.getType());

            // 5. 注入依赖
            field.setAccessible(true);
            field.set(orderService, dependency);
        }
    }

    // 6. 返回完整注入的Bean
    return orderService;
}

三种注入方式:

// 1. 字段注入(最常用)
@Component
public class UserService {
    @Autowired
    private UserRepository userRepository;
}

// 2. 构造器注入(推荐,便于测试)
@Component
public class UserService {
    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

// 3. Setter注入(不推荐)
@Component
public class UserService {
    private UserRepository userRepository;

    @Autowired
    public void setUserRepository(UserRepository userRepository) {
        this.userRepository = userRepository;
    }
}

处理循环依赖:

// 循环依赖的问题
@Component
public class ServiceA {
    @Autowired
    private ServiceB serviceB;  // A依赖B
}

@Component
public class ServiceB {
    @Autowired
    private ServiceA serviceA;  // B依赖A
}

// Spring的解决方案:三级缓存
public class CircularDependencyDemo {
    // 第一级缓存:完整的Bean
    private Map<String, Object> singletonObjects = new HashMap<>();

    // 第二级缓存:半成品Bean(已创建但未注入)
    private Map<String, Object> earlySingletonObjects = new HashMap<>();

    // 第三级缓存:Bean工厂
    private Map<String, ObjectFactory<?>> singletonFactories = new HashMap<>();

    // 解决流程:
    // 1. 创建ServiceA实例,放入第二级缓存
    // 2. ServiceA需要ServiceB,开始创建ServiceB
    // 3. 创建ServiceB实例,放入第二级缓存
    // 4. ServiceB需要ServiceA,从第二级缓存获取(已存在)
    // 5. ServiceB注入完成,放入第一级缓存
    // 6. ServiceA注入完成,放入第一级缓存
}

4.5 第四阶段:初始化Bean

// Bean初始化的过程

@Component
public class UserService implements InitializingBean {
    @Autowired
    private UserRepository userRepository;

    // 1. 执行@PostConstruct方法
    @PostConstruct
    public void init() {
        System.out.println("1. @PostConstruct方法执行");
        // 初始化逻辑
    }

    // 2. 执行InitializingBean接口的afterPropertiesSet方法
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("2. InitializingBean.afterPropertiesSet()执行");
        // 初始化逻辑
    }

    // 3. 执行initMethod(在@Bean中指定)
    public void customInit() {
        System.out.println("3. initMethod执行");
        // 初始化逻辑
    }
}

// 在配置类中指定initMethod
@Configuration
public class AppConfig {
    @Bean(initMethod = "customInit")
    public UserService userService() {
        return new UserService();
    }
}

// 4. BeanPostProcessor的前置和后置方法
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("4. BeanPostProcessor.postProcessBeforeInitialization()");
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("5. BeanPostProcessor.postProcessAfterInitialization()");
        // 这里可以进行代理增强
        return bean;
    }
}

// 执行顺序:
// 1. @PostConstruct
// 2. InitializingBean.afterPropertiesSet()
// 3. initMethod
// 4. BeanPostProcessor.postProcessBeforeInitialization()
// 5. BeanPostProcessor.postProcessAfterInitialization()

第四部分:IOC容器的核心组件

五、BeanFactory与ApplicationContext

5.1 两者的关系

┌──────────────────────────────────────────┐
│    BeanFactoryApplicationContext        │
├──────────────────────────────────────────┤
│                                          │
│  BeanFactory(低级容器)                  │
│  ├─ 职责:创建和管理Bean                  │
│  ├─ 功能:基础的Bean生命周期管理          │
│  ├─ 性能:轻量级                         │
│  └─ 用途:底层框架                       │
│                                          │
│  ApplicationContext(高级容器)           │
│  ├─ 继承:extends BeanFactory             │
│  ├─ 职责:提供更多企业级功能              │
│  ├─ 功能:                               │
│  │   ├─ Bean生命周期管理                  │
│  │   ├─ 国际化支持                       │
│  │   ├─ 事件发布                         │
│  │   ├─ 资源加载                         │
│  │   └─ AOP支持                          │
│  ├─ 性能:相对较重                       │
│  └─ 用途:应用程序                       │
│                                          │
└──────────────────────────────────────────┘

5.2 ApplicationContext的实现类

// 1. ClassPathXmlApplicationContext - 从classpath加载XML配置
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

// 2. FileSystemXmlApplicationContext - 从文件系统加载XML配置
ApplicationContext context = new FileSystemXmlApplicationContext("/path/to/applicationContext.xml");

// 3. AnnotationConfigApplicationContext - 从注解配置类加载
ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

// 4. AnnotationConfigWebApplicationContext - Web应用的注解配置
// 在Spring MVC中使用

// 5. WebApplicationContext - Web应用的容器
// 通过DispatcherServlet创建

5.3 BeanFactory的工作原理

public class BeanFactoryDemo {
    public static void main(String[] args) {
        // 1. 创建BeanFactory
        BeanFactory beanFactory = new DefaultListableBeanFactory();

        // 2. 注册BeanDefinition
        BeanDefinition beanDef = new RootBeanDefinition(UserService.class);
        ((DefaultListableBeanFactory) beanFactory).registerBeanDefinition("userService", beanDef);

        // 3. 获取Bean(延迟初始化)
        UserService userService = beanFactory.getBean("userService", UserService.class);

        // BeanFactory特点:
        // - 延迟初始化:getBean时才创建
        // - 轻量级:只管理Bean的创建
        // - 不支持国际化、事件等高级功能
    }
}

第五部分:IOC的实际应用

六、Spring中的IOC应用

6.1 组件扫描和自动装配

// 1. 定义配置类
@Configuration
@ComponentScan(basePackages = "com.example")
public class AppConfig {
}

// 2. 定义Bean
@Component
public class UserRepository {
    public User findById(int id) {
        return new User(id, "Tom");
    }
}

@Service
public class UserService {
    @Autowired
    private UserRepository userRepository;

    public User getUser(int id) {
        return userRepository.findById(id);
    }
}

@Controller
public class UserController {
    @Autowired
    private UserService userService;

    public void handleRequest(int id) {
        User user = userService.getUser(id);
    }
}

// 3. 启动容器
public class Application {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 4. 获取Bean
        UserController controller = context.getBean(UserController.class);
        controller.handleRequest(1);
    }
}

// Spring的处理流程:
// 1. 扫描@ComponentScan指定的包
// 2. 找到@Component及其衍生注解(@Service、@Controller等)
// 3. 为每个类创建BeanDefinition
// 4. 创建Bean实例
// 5. 通过@Autowired注入依赖
// 6. 执行初始化方法
// 7. Bean准备就绪

6.2 条件装配

// 根据条件选择不同的Bean实现

// 1. 定义接口
public interface DataSource {
    Connection getConnection();
}

// 2. 定义多个实现
@Component
@ConditionalOnProperty(name = "db.type", havingValue = "mysql")
public class MysqlDataSource implements DataSource {
    @Override
    public Connection getConnection() {
        return new MysqlConnection();
    }
}

@Component
@ConditionalOnProperty(name = "db.type", havingValue = "postgresql")
public class PostgresqlDataSource implements DataSource {
    @Override
    public Connection getConnection() {
        return new PostgresqlConnection();
    }
}

// 3. 注入时自动选择
@Service
public class UserService {
    @Autowired
    private DataSource dataSource;  // 根据配置自动选择实现
}

// 4. 配置文件
// application.properties
// db.type=mysql

6.3 Bean的作用域

// 1. Singleton(单例)- 默认
@Component
@Scope("singleton")
public class SingletonBean {
    // 整个应用只有一个实例
}

// 2. Prototype(原型)
@Component
@Scope("prototype")
public class PrototypeBean {
    // 每次获取都创建新实例
}

// 3. Request(请求作用域)- Web应用
@Component
@Scope("request")
public class RequestBean {
    // 每个HTTP请求创建一个实例
}

// 4. Session(会话作用域)- Web应用
@Component
@Scope("session")
public class SessionBean {
    // 每个HTTP会话创建一个实例
}

// 验证作用域
public class ScopeDemo {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // Singleton验证
        SingletonBean bean1 = context.getBean(SingletonBean.class);
        SingletonBean bean2 = context.getBean(SingletonBean.class);
        System.out.println(bean1 == bean2);  // true,同一个实例

        // Prototype验证
        PrototypeBean bean3 = context.getBean(PrototypeBean.class);
        PrototypeBean bean4 = context.getBean(PrototypeBean.class);
        System.out.println(bean3 == bean4);  // false,不同实例
    }
}

6.4 Bean的生命周期管理

// Bean的完整生命周期

@Component
public class LifecycleBean implements InitializingBean, DisposableBean {
    private String name;

    // 1. 构造函数
    public LifecycleBean() {
        System.out.println("1. 构造函数执行");
    }

    // 2. 属性注入(通过反射)
    public void setName(String name) {
        System.out.println("2. 属性注入");
        this.name = name;
    }

    // 3. BeanNameAware接口
    @Override
    public void setBeanName(String name) {
        System.out.println("3. setBeanName()执行");
    }

    // 4. BeanFactoryAware接口
    @Override
    public void setBeanFactory(BeanFactory beanFactory) {
        System.out.println("4. setBeanFactory()执行");
    }

    // 5. ApplicationContextAware接口
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) {
        System.out.println("5. setApplicationContext()执行");
    }

    // 6. BeanPostProcessor的前置方法
    // 由Spring框架调用

    // 7. @PostConstruct注解
    @PostConstruct
    public void init() {
        System.out.println("7. @PostConstruct执行");
    }

    // 8. InitializingBean接口
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("8. InitializingBean.afterPropertiesSet()执行");
    }

    // 9. BeanPostProcessor的后置方法
    // 由Spring框架调用

    // 10. 正常使用
    public void doSomething() {
        System.out.println("10. Bean正常使用");
    }

    // 11. @PreDestroy注解
    @PreDestroy
    public void cleanup() {
        System.out.println("11. @PreDestroy执行");
    }

    // 12. DisposableBean接口
    @Override
    public void destroy() throws Exception {
        System.out.println("12. DisposableBean.destroy()执行");
    }
}

// 执行顺序:
// 1. 构造函数
// 2. 属性注入
// 3. setBeanName()
// 4. setBeanFactory()
// 5. setApplicationContext()
// 6. BeanPostProcessor.postProcessBeforeInitialization()
// 7. @PostConstruct
// 8. InitializingBean.afterPropertiesSet()
// 9. BeanPostProcessor.postProcessAfterInitialization()
// 10. Bean正常使用
// 11. @PreDestroy
// 12. DisposableBean.destroy()

第六部分:IOC与其他机制的结合

七、IOC与AOP的结合

// IOC创建Bean,AOP为Bean增强

// 1. 定义业务接口
public interface UserService {
    void save(User user);
}

// 2. 实现业务接口
@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserRepository userRepository;

    @Override
    @Transactional
    public void save(User user) {
        userRepository.save(user);
    }
}

// 3. 定义切面
@Aspect
@Component
public class LoggingAspect {
    @Before("execution(* com.example.service.*.*(..))")
    public void beforeMethod(JoinPoint joinPoint) {
        System.out.println("方法调用前:" + joinPoint.getSignature());
    }

    @After("execution(* com.example.service.*.*(..))")
    public void afterMethod(JoinPoint joinPoint) {
        System.out.println("方法调用后:" + joinPoint.getSignature());
    }
}

// 4. IOC和AOP的协作
public class IOCAndAOPDemo {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // IOC创建Bean
        UserService userService = context.getBean(UserService.class);

        // 实际上获取的是代理对象
        System.out.println(userService.getClass().getName());
        // 输出:com.sun.proxy.$Proxy0(JDK动态代理)
        // 或:com.example.UserServiceImpl$$EnhancerByCGLIB$$xxx(CGLIB代理)

        // 调用方法时,AOP会织入增强逻辑
        userService.save(new User());
        // 输出:
        // 方法调用前:...
        // 保存用户
        // 方法调用后:...
    }
}

// IOC和AOP的工作流程:
// 1. IOC扫描@Service注解,创建UserServiceImpl的BeanDefinition
// 2. IOC创建UserServiceImpl实例
// 3. IOC注入依赖
// 4. AOP检测到@Transactional注解
// 5. AOP创建代理对象,包装UserServiceImpl
// 6. 将代理对象放入容器
// 7. 调用代理对象的方法时,AOP织入增强逻辑

八、IOC与注解的结合

// 注解驱动的IOC

// 1. 元注解定义
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyService {
    String value() default "";
}

// 2. 自定义注解处理器
@Component
public class MyServiceBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                                       BeanDefinitionRegistry registry) {
        // 扫描@MyService注解
        ClassPathBeanDefinitionScanner scanner = new ClassPathBeanDefinitionScanner(registry);
        scanner.addIncludeFilter((metadataReader, metadataReaderFactory) -> {
            return metadataReader.getClassMetadata()
                .hasAnnotation(MyService.class.getName());
        });

        // 注册BeanDefinition
        scanner.scan("com.example");
    }
}

// 3. 使用自定义注解
@MyService("userService")
public class UserService {
    public void save(User user) {
        System.out.println("保存用户");
    }
}

// 4. 注解驱动的依赖注入
@MyService("orderService")
public class OrderService {
    @Autowired
    private UserService userService;

    public void createOrder(Order order) {
        userService.save(order.getUser());
    }
}

// Spring通过反射读取注解,自动完成Bean的创建和注入

第七部分:IOC的性能与最佳实践

九、IOC的性能考虑

9.1 启动性能

// IOC容器启动的性能开销

public class StartupPerformanceDemo {
    public static void main(String[] args) {
        // 测试启动时间
        long startTime = System.currentTimeMillis();

        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        long endTime = System.currentTimeMillis();
        System.out.println("容器启动耗时:" + (endTime - startTime) + "ms");

        // 性能开销来自:
        // 1. 类扫描 - 扫描classpath中的所有类
        // 2. 注解解析 - 通过反射读取注解信息
        // 3. BeanDefinition创建 - 为每个Bean创建定义
        // 4. Bean实例化 - 通过反射创建实例
        // 5. 依赖注入 - 递归注入所有依赖
        // 6. 初始化方法执行 - 执行@PostConstruct等
    }
}

9.2 性能优化建议

// 1. 使用懒加载
@Component
@Lazy
public class HeavyBean {
    // 只在第一次使用时才创建
}

// 2. 缩小扫描范围
@Configuration
@ComponentScan(basePackages = "com.example.service")  // 只扫描service包
public class AppConfig {
}

// 3. 使用@Bean而不是@Component
@Configuration
public class AppConfig {
    @Bean
    public UserService userService() {
        // 显式创建,避免注解扫描
        return new UserService();
    }
}

// 4. 避免循环依赖
// 循环依赖会增加初始化时间
// 应该重新设计架构避免循环依赖

// 5. 使用条件装配减少Bean数量
@Component
@ConditionalOnProperty(name = "feature.enabled", havingValue = "true")
public class OptionalBean {
    // 只在特定条件下创建
}

// 6. 使用Spring Boot的自动配置
// Spring Boot已经优化了启动性能
@SpringBootApplication
public class Application {
    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }
}

十、IOC的最佳实践

10.1 推荐做法

// 1. 优先使用构造器注入
@Service
public class UserService {
    private final UserRepository userRepository;
    private final UserValidator userValidator;

    // 构造器注入的优势:
    // - 依赖不可变
    // - 便于测试
    // - 清晰表达依赖关系
    public UserService(UserRepository userRepository, UserValidator userValidator) {
        this.userRepository = userRepository;
        this.userValidator = userValidator;
    }
}

// 2. 依赖接口而不是实现
@Service
public class OrderService {
    private final PaymentService paymentService;  // 依赖接口

    public OrderService(PaymentService paymentService) {
        this.paymentService = paymentService;
    }
}

// 3. 使用@Qualifier消除歧义
@Service
public class OrderService {
    @Autowired
    @Qualifier("alipayService")
    private PaymentService paymentService;
}

// 4. 为Bean提供有意义的名称
@Service("userService")  // 明确指定Bean名称
public class UserServiceImpl implements UserService {
}

// 5. 使用配置类而不是XML
@Configuration
public class AppConfig {
    @Bean
    public UserRepository userRepository() {
        return new UserRepositoryImpl();
    }

    @Bean
    public UserService userService(UserRepository userRepository) {
        return new UserServiceImpl(userRepository);
    }
}

// 6. 合理使用作用域
@Service
@Scope("singleton")  // 大多数情况下使用单例
public class UserService {
}

// 7. 实现接口便于测试和扩展
public interface UserService {
    void save(User user);
}

@Service
public class UserServiceImpl implements UserService {
    @Override
    public void save(User user) {
    }
}

// 8. 使用@Autowired(required = false)处理可选依赖
@Service
public class UserService {
    @Autowired(required = false)
    private UserCache userCache;  // 可选依赖
}

// 9. 避免在Bean中使用静态变量
// ❌ 不好的做法
@Service
public class UserService {
    private static UserRepository userRepository;  // 静态变量
}

// ✅ 好的做法
@Service
public class UserService {
    private final UserRepository userRepository;  // 实例变量
}

// 10. 使用@ConfigurationProperties进行配置
@Component
@ConfigurationProperties(prefix = "app.user")
public class UserProperties {
    private String defaultName;
    private int defaultAge;

    // getter/setter
}

10.2 避免做法

// ❌ 不要使用字段注入
@Service
public class BadUserService {
    @Autowired
    private UserRepository userRepository;  // 字段注入

    // 问题:
    // 1. 依赖隐藏,不清楚需要什么
    // 2. 难以测试,无法通过构造器传入mock对象
    // 3. 可能为null,容易出现NPE
    // 4. 依赖可变,容易被修改
}

// ❌ 不要在Bean中创建其他Bean
@Service
public class BadOrderService {
    public void createOrder(Order order) {
        // ❌ 不要这样做
        UserService userService = new UserService();
        userService.save(order.getUser());
    }
}

// ✅ 应该注入
@Service
public class GoodOrderService {
    private final UserService userService;

    public GoodOrderService(UserService userService) {
        this.userService = userService;
    }

    public void createOrder(Order order) {
        userService.save(order.getUser());
    }
}

// ❌ 不要在Bean中使用ApplicationContext.getBean()
@Service
public class BadService {
    @Autowired
    private ApplicationContext applicationContext;

    public void doSomething() {
        // ❌ 不要这样做
        UserService userService = applicationContext.getBean(UserService.class);
    }
}

// ✅ 应该直接注入
@Service
public class GoodService {
    private final UserService userService;

    public GoodService(UserService userService) {
        this.userService = userService;
    }
}

// ❌ 不要创建过多的单例Bean
@Configuration
public class BadConfig {
    @Bean
    public Bean1 bean1() { return new Bean1(); }
    @Bean
    public Bean2 bean2() { return new Bean2(); }
    // ... 创建100个Bean
    // 问题:启动慢,内存占用大
}

// ✅ 应该按需创建
@Configuration
public class GoodConfig {
    @Bean
    @ConditionalOnProperty(name = "feature.enabled")
    public OptionalBean optionalBean() {
        return new OptionalBean();
    }
}

// ❌ 不要在Bean中做重操作
@Component
public class BadBean {
    public BadBean() {
        // ❌ 不要在构造函数中做重操作
        loadLargeFile();
        queryDatabase();
    }
}

// ✅ 应该在初始化方法中做
@Component
public class GoodBean {
    @PostConstruct
    public void init() {
        // ✅ 在@PostConstruct中做重操作
        loadLargeFile();
        queryDatabase();
    }
}

// ❌ 不要创建循环依赖
@Service
public class ServiceA {
    @Autowired
    private ServiceB serviceB;  // A依赖B
}

@Service
public class ServiceB {
    @Autowired
    private ServiceA serviceA;  // B依赖A
}

// ✅ 应该重新设计避免循环依赖
@Service
public class ServiceA {
    @Autowired
    private ServiceC serviceC;
}

@Service
public class ServiceB {
    @Autowired
    private ServiceC serviceC;
}

@Service
public class ServiceC {
    // 不依赖A和B
}

第八部分:IOC的高级特性

十一、Bean的条件装配

// 根据条件选择不同的Bean

// 1. @ConditionalOnProperty - 根据配置属性
@Component
@ConditionalOnProperty(name = "cache.enabled", havingValue = "true")
public class CacheService {
    // 只在cache.enabled=true时创建
}

// 2. @ConditionalOnClass - 根据类是否存在
@Component
@ConditionalOnClass(name = "redis.clients.jedis.Jedis")
public class RedisService {
    // 只在Redis客户端库存在时创建
}

// 3. @ConditionalOnMissingBean - 根据Bean是否存在
@Configuration
public class AppConfig {
    @Bean
    @ConditionalOnMissingBean
    public UserRepository userRepository() {
        return new DefaultUserRepository();
    }
}

// 4. @ConditionalOnExpression - 根据SpEL表达式
@Component
@ConditionalOnExpression("${feature.enabled:false}")
public class FeatureService {
    // 只在表达式为true时创建
}

// 5. 自定义Condition
public class MyCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // 自定义条件逻辑
        return context.getEnvironment().getProperty("my.feature").equals("enabled");
    }
}

@Component
@Conditional(MyCondition.class)
public class MyService {
    // 只在自定义条件满足时创建
}

十二、Bean的事件机制

// Spring IOC支持事件发布和监听

// 1. 定义事件
public class UserCreatedEvent extends ApplicationEvent {
    private final User user;

    public UserCreatedEvent(Object source, User user) {
        super(source);
        this.user = user;
    }

    public User getUser() {
        return user;
    }
}

// 2. 发布事件
@Service
public class UserService {
    @Autowired
    private ApplicationEventPublisher eventPublisher;

    public void createUser(User user) {
        // 保存用户
        userRepository.save(user);

        // 发布事件
        eventPublisher.publishEvent(new UserCreatedEvent(this, user));
    }
}

// 3. 监听事件
@Component
public class UserCreatedListener implements ApplicationListener<UserCreatedEvent> {
    @Override
    public void onApplicationEvent(UserCreatedEvent event) {
        User user = event.getUser();
        System.out.println("用户创建事件:" + user.getName());

        // 发送邮件、记录日志等
    }
}

// 4. 使用@EventListener注解
@Component
public class UserEventHandler {
    @EventListener
    public void handleUserCreated(UserCreatedEvent event) {
        System.out.println("用户创建:" + event.getUser().getName());
    }

    @EventListener
    public void handleUserDeleted(UserDeletedEvent event) {
        System.out.println("用户删除:" + event.getUser().getName());
    }
}

十三、Bean的后处理器

// BeanPostProcessor用于在Bean初始化前后进行处理

// 1. 实现BeanPostProcessor接口
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) {
        System.out.println("初始化前:" + beanName);
        // 可以在这里修改Bean
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("初始化后:" + beanName);
        // 可以在这里创建代理
        if (bean instanceof UserService) {
            return createProxy(bean);
        }
        return bean;
    }

    private Object createProxy(Object bean) {
        // 创建代理对象
        return Proxy.newProxyInstance(
            bean.getClass().getClassLoader(),
            bean.getClass().getInterfaces(),
            (proxy, method, args) -> {
                System.out.println("代理方法:" + method.getName());
                return method.invoke(bean, args);
            }
        );
    }
}

// 2. BeanFactoryPostProcessor - 处理BeanDefinition
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) {
        // 可以在这里修改BeanDefinition
        BeanDefinition beanDef = beanFactory.getBeanDefinition("userService");
        beanDef.setScope("prototype");  // 改为原型作用域
    }
}

第九部分:总结

十四、IOC的本质思考

IOC(控制反转)是一种设计思想,通过将对象的创建权和依赖管理权交给框架容器,实现了代码的解耦、灵活性和可维护性的提升。

┌──────────────────────────────────────────┐
│         IOC的核心价值                     │
├──────────────────────────────────────────┤
│                                          │
│  1. 解耦                                  │
│     ├─ 依赖接口而不是实现                │
│     ├─ 实现类可以随意替换                │
│     └─ 修改不会影响调用方                │
│                                          │
│  2. 灵活性                                │
│     ├─ 通过配置选择不同实现              │
│     ├─ 支持条件装配                      │
│     └─ 支持动态代理和增强                │
│                                          │
│  3. 可测试性                              │
│     ├─ 容易mock依赖                      │
│     ├─ 支持单元测试                      │
│     └─ 支持集成测试                      │
│                                          │
│  4. 自动化                                │
│     ├─ 自动创建对象                      │
│     ├─ 自动注入依赖                      │
│     └─ 自动管理生命周期                  │
│                                          │
│  5. 可维护性                              │
│     ├─ 配置集中管理                      │
│     ├─ 易于扩展                          │
│     └─ 代码更清晰                        │
│                                          │
└──────────────────────────────────────────┘

十五、IOC的四个阶段总结

┌──────────────────────────────────────────┐
│      IOC的四个阶段总结                    │
├──────────────────────────────────────────┤
│                                          │
│  第1阶段:容器启动                        │
│  ├─ 加载配置文件/配置类                  │
│  ├─ 创建IOC容器实例                      │
│  └─ 准备开始管理Bean                     │
│                                          │
│  第2阶段:Bean定义注册                    │
│  ├─ 扫描类路径                           │
│  ├─ 读取注解或XML配置                    │
│  ├─ 创建BeanDefinition                   │
│  └─ 注册到容器                           │
│                                          │
│  第3阶段:实例化和依赖注入                │
│  ├─ 通过反射创建Bean实例                 │
│  ├─ 递归注入依赖                         │
│  ├─ 支持多种注入方式                     │
│  └─ 处理循环依赖                         │
│                                          │
│  第4阶段:初始化Bean                      │
│  ├─ 执行@PostConstruct方法               │
│  ├─ 执行InitializingBean接口             │
│  ├─ 执行BeanPostProcessor                │
│  └─ Bean准备就绪                         │
│                                          │
└──────────────────────────────────────────┘

十六、IOC与反射、动态代理的关系

┌──────────────────────────────────────────┐
│    IOC、反射、动态代理的关系              │
├──────────────────────────────────────────┤
│                                          │
│  反射(Reflection)                       │
│  ├─ 本质:运行时获取类信息                │
│  ├─ 作用:IOC的基础                      │
│  └─ 用途:创建对象、注入依赖              │
│                                          │
│  IOC(Inversion of Control)             │
│  ├─ 本质:控制权反转                      │
│  ├─ 作用:自动创建和管理Bean             │
│  └─ 用途:解耦、灵活、可维护              │
│                                          │
│  动态代理(Dynamic Proxy)                │
│  ├─ 本质:运行时生成代理类                │
│  ├─ 作用:AOP的基础                      │
│  └─ 用途:织入增强逻辑                    │
│                                          │
│  三者的协作:                             │
│  ├─ 反射:IOC用反射创建对象               │
│  ├─ IOC:创建Bean并注入依赖               │
│  ├─ 动态代理:为Bean创建代理              │
│  └─ AOP:通过代理织入增强逻辑             │
│                                          │
└──────────────────────────────────────────┘

十七、关键要点回顾

17.1 IOC的核心概念

概念 说明 用途
BeanFactory 低级容器 基础Bean管理
ApplicationContext 高级容器 企业级应用
BeanDefinition Bean的定义 描述Bean的元信息
Bean 容器管理的对象 应用中的业务对象
依赖注入 自动注入依赖 解耦和灵活
作用域 Bean的生命周期 singleton/prototype等

17.2 三种注入方式对比

方式 优点 缺点 推荐度
构造器注入 依赖清晰、不可变、易测试 参数多时复杂 ⭐⭐⭐⭐⭐
字段注入 简洁 隐藏依赖、难测试、可变
Setter注入 灵活 依赖可变、不清晰 ⭐⭐

17.3 Bean的生命周期

构造函数 → 属性注入 → Aware接口 → BeanPostProcessor前置
→ @PostConstructInitializingBeanBeanPostProcessor后置
→ 正常使用 → @PreDestroyDisposableBean

十八、记忆口诀

IOC是思想,容器来管理
Bean的创建,依赖的注入
四个阶段走,启动注册实例化
初始化完成,Bean就准备好

反射是基础,动态代理增强
AOP织入逻辑,框架自动完成
程序员声明,框架来实现

构造器注入最推荐,字段注入要避免
依赖接口不实现,灵活扩展最关键
单例默认用,原型按需要

BeanFactory轻量级,ApplicationContext功能全
启动会慢点,但好处多得很
解耦灵活可扩展,可维护性最关键

十九、相关链接


二十、常见问题解答

Q1: IOC和DI有什么区别?

答:

  • IOC(控制反转) - 是一种设计思想,强调控制权的反转
  • DI(依赖注入) - 是实现IOC的一种方式,强调依赖的注入
  • 关系:IOC是目标,DI是手段

Q2: 为什么Spring默认使用单例而不是原型?

答:

  • 单例性能更好,避免频繁创建对象
  • 单例内存占用少
  • 大多数Bean是无状态的,可以安全共享
  • 如果Bean有状态,应该使用原型或其他作用域

Q3: 循环依赖为什么会发生?

答:

A依赖BB依赖A
或者更复杂的链式依赖:AB→C→A

Q4: Spring如何解决循环依赖?

答:

  • 使用三级缓存机制
  • 第一级:完整的Bean
  • 第二级:半成品Bean(已创建但未注入)
  • 第三级:Bean工厂

Q5: 为什么推荐使用构造器注入?

答:

  • 依赖清晰,一目了然
  • 依赖不可变,线程安全
  • 便于单元测试
  • 强制依赖必须提供

Q6: @Autowired和@Resource有什么区别?

答:

  • @Autowired - Spring提供,按类型注入
  • @Resource - Java标准,按名称注入
  • 推荐使用@Autowired

⬅️ 00-Spring总览 🏠 00-Java ➡️ 依赖注入(DI)